package com.unibeta.vrules.engines.dccimpls.compiler;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.unibeta.vrules.engines.dccimpls.compiler.memory.MemoryClassLoader;
import com.unibeta.vrules.parsers.ConfigurationProxy;
import com.unibeta.vrules.utils.CommonUtils;

public class MemoryInnerValidationClassLoader extends MemoryClassLoader{

	private static Logger log = LoggerFactory.getLogger(ExternalStreamedValidationClassLoader.class);
	public static final String COM_UNIBETA_VRULES_ENGINES_DCCIMPLS_RULES = "com.unibeta.vrules.engines.dccimpls.rules.";

	Map<String, byte[]> classBytes;
	private Class decisionClass = null;
	private String className;

	private static Map<String, Queue<Object>> instancesPool = Collections
			.synchronizedMap(new HashMap<String, Queue<Object>>());
	

	public MemoryInnerValidationClassLoader(String className, Map<String, byte[]> classBytes, Class decisionClass) {
		super(classBytes);
		
		this.className = className;
		this.classBytes = classBytes;
		this.decisionClass = decisionClass;
		
	}

	/**
	 * Creates a new validation instance by given rules configuration file name.
	 * 
	 * @param className the rules configuration fiame name.
	 * @return the instance of class
	 * @throws ClassNotFoundException
	 * @throws Exception
	 */
	public Object newValidationInstance() throws ClassNotFoundException {
		

		Object instance = null;
		String classRUIName = buildClassPath();

		try {
			Class clazzDcc = super.findClass(classRUIName);
			Object obj = clazzDcc.newInstance();
			instance = obj;

			synchronized (classRUIName) {
				if (instancesPool.get(getKey(classRUIName)) == null) {
					instancesPool.put(getKey(classRUIName), new LinkedBlockingQueue());
				}

				instancesPool.get(getKey(classRUIName)).clear();
				instancesPool.get(getKey(classRUIName)).add(instance);
			}
		} catch (InstantiationException e) {
			log.error(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			log.error(e.getMessage(), e);
		} catch(Throwable t) {
			t.printStackTrace();
			log.error(t.getMessage(), t);
		}

		if(instancesPool.get(getKey(classRUIName)) != null) {
			return instancesPool.get(getKey(classRUIName)).poll();
		}else {
			return null;
		}
		
	}

	private String getKey(String classRUIName) {
		return "@" + ConfigurationProxy.buildKeyValue(classRUIName, decisionClass);
	}

	private String buildClassPath() {

//		return COM_UNIBETA_VRULES_ENGINES_DCCIMPLS_RULES
//				+ CommonUtils.getFileSimpleName(className);
		
		return className;
	}

	 /**
     * Gets current availabe validation instance directly.
     * 
     * @return
     * @throws Exception
     */
    public Object getValidationInstance() throws ClassNotFoundException {

    	Object instance = null;
    	Queue queue = null;
    	
        queue = instancesPool.get(getKey(buildClassPath()));

        if (null == queue) {
        	instance = newValidationInstance();
        }else {
        	instance = queue.poll();
        	if(instance == null) {
        		instance = newValidationInstance();
        	}
        }
        
        return instance;
    }

    public boolean offerValidationInstance(Object obj) {
    	Queue queue = instancesPool.get(getKey( buildClassPath()));
           
         if (null != queue && null != obj) {
        	return queue.offer(obj);
         }
         
         return true;
    }
}
